package com.zliuyno.io.testreactor;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.Channel;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author liuyno
 * @date 2020/11/25 - 19:56
 */
public class SelectorThreadGroup {
    SelectorThread[] sts;
    ServerSocketChannel server = null;
    AtomicInteger xid = new AtomicInteger(0);

    SelectorThreadGroup stg = this;

    SelectorThreadGroup(int num) {
        //num线程数
        sts = new SelectorThread[num];
        for (int i = 0; i < num; i++) {
            sts[i] = new SelectorThread(this);
            new Thread(sts[i]).start();
        }

    }


    public void bind(int port) {
        try {
            server = ServerSocketChannel.open();
            server.configureBlocking(false);
            server.bind(new InetSocketAddress(port));

            //注册到那个selector上呢？
//            nextSelector(server);
            nextSelectorV3(server);
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

    public void nextSelectorV3(Channel c) {
        try {
            if (c instanceof ServerSocketChannel) {
                SelectorThread st = next();
                st.lbq.put(c);
                st.setWorker(stg);
                st.selector.wakeup();
            } else {
                SelectorThread st = nextV3();


                st.lbq.add(c);
                st.selector.wakeup();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }


    public void nextSelector(Channel c) {
        SelectorThread st = next(); //在main线程中，取到堆里的selectorThread对象
        //c有可能是server 有可能是client
        //1.通过队列传递数据、消息
        st.lbq.add(c);
        //2.打破阻塞，让对应的线程去自己在被唤醒后做一些事情
        st.selector.wakeup();

        /*
        ServerSocketChannel s = (ServerSocketChannel) c;
        try {
            //呼应上 int nums = selector.select();   //阻塞    wakeup()
            s.register(st.selector, SelectionKey.OP_ACCEPT);    //会被阻塞的
            st.selector.wakeup();   //功能是让selector的select()方法立刻返回，不阻塞！
            System.out.println("下一行代码被阻塞");
        } catch (ClosedChannelException e) {
            e.printStackTrace();
        }*/

    }

    private SelectorThread nextV3() {
        int index = xid.incrementAndGet() % stg.sts.length;
        return stg.sts[index];
    }

    //无论你的 serverSocket socket 都复用这个方法
    public SelectorThread next() {
        int index = xid.incrementAndGet() % sts.length;
        return sts[index];
    }

    public void setWorker(SelectorThreadGroup stg) {
        this.stg = stg;
    }
}
